﻿using System;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

using Noris.Tools.TraceVisualiser.Support;

namespace Noris.Tools.TraceVisualiser.Components
{
	// POKRAČOVÁNÍ TŘÍDY GridGraphCls : KRESLENÍ ELEMENTŮ
	/// <summary>
	/// Třída pro zobrazování grafu některého typu v rámci gridu
	/// </summary>
	internal partial class GridGraphCls : DblGraphControl
	{
		/// <summary>
		/// Vstupní metoda pro kreslení libovolného elementu.
		/// </summary>
		/// <param name="elementKey"></param>
		/// <param name="args"></param>
		private void _PaintRowGraphElement(GraphElementPainterArgs args)
		{
            if (args.GraphMode == RowGraphMode.UserDraw || args.DataElement.ElementShapeType == GraphElementShapeType.UserDraw)
                // User Draw (user může buď element sám nakreslit, anebo může nadefinovat data do args, a pak se zde vykreslí):
                args.DataElement.DrawElement(args);
            else
                // Standard Draw (příprava dat v args tak, aby metoda _PaintElementDefault() vykreslila všechny potřebné vizuální prvky):
                this._PaintElementPrepare(args);

            // Standardní vykreslení podle dat v args:
            this._PaintElementDefault(args);
		}
        #region TVORBA STANDARDNÍCH DAT PRO KRESLENÍ ELEMENTŮ - DEFINICE DAT DO args (ZDE SE NEKRESLÍ)
        /// <summary>
        /// Příprava dat do args pro standardní tvary elementu, mimo UserDraw()
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPrepare(GraphElementPainterArgs args)
        {
            if (args.LayerType == GraphLayerType.ElementTempLayer)
                this._PaintElementPrepareTemp(args);
            else
            {
                switch (args.GraphMode)
                {
                    case RowGraphMode.SingleTask:
                        this._PaintElementPrepareSingleTask(args);
                        break;
                    case RowGraphMode.Percentage:
                        this._PaintElementPreparePercentage(args);
                        break;
                    case RowGraphMode.MultiTask:
                        this._PaintElementPrepareMultiTask(args);
                        break;
					case RowGraphMode.BarGraph:
						this._PaintElementPrepareBarGraph(args);
                        break;
                    default:
                        throw new NotImplementedException("Metoda _PaintElementPrepare() není implementována pro graf " + args.GraphMode.ToString());
                }
            }
        }
        /// <summary>
        /// Příprava pro kreslení elementu TempLayer
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPrepareTemp(GraphElementPainterArgs args)
        {
            // Vlastní prostor reprezentace grafu:
            args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
            args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
            args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

            // Řeknu, co všechno chci vykreslit:
            args.BackGroundRunSystem = true;
            args.BackGroundRectangle = args.DetailArea;              // Prostor pro výplň
            // args.BackGroundColor = Color.Empty;                   // Když nenadefinuji barvu, vygeneruje se defaultní brush

			this._PaintElementPrepareImage(args);                    // Kreslení Image
        }
        /// <summary>
        /// Příprava pro kreslení elementu grafu Gantt
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPrepareSingleTask(GraphElementPainterArgs args)
        {
            switch (args.ElementShapeType)
            {
                case GraphElementShapeType.Hexagon:
                    this._PaintElementPrepareSingleTaskHexagon(args);
                    break;
                case GraphElementShapeType.RightTriangle:
                    this._PaintElementPrepareSingleTaskRightTriangle(args);
                    break;
                case GraphElementShapeType.Rectangle:
                default:
                    this._PaintElementPrepareSingleTaskRectangle(args);
                    break;
            }
        }
        /// <summary>
        /// Příprava pro kreslení elementu grafu Gantt, tvar elementu Rectangle
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPrepareSingleTaskRectangle(GraphElementPainterArgs args)
        {
            // Vlastní prostor reprezentace grafu:
            args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
            args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
            args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

            // Pozadí:
            args.BackGroundRunSystem = true;
            args.BackGroundRectangle = args.DetailArea;
            // args.BackGroundColor = Color.LightSkyBlue;

            // Výplň podle sumáře časů:
            Rectangle detailArea = args.DetailArea;
            bool showFragment = (args.ElementState == GraphElementState.OnMouse || args.ElementState == GraphElementState.Selected || args.ElementState == GraphElementState.Active);
            if (showFragment && detailArea.Width > 7 && args.DataElement.Fragments != null)
            {

                float sumFragment = 0F;
                foreach (float fragment in args.DataElement.Fragments)
                    sumFragment += fragment;
                if (sumFragment > 0F)
                {
                    Rectangle fragmentBase = detailArea;
                    float fW = (float)fragmentBase.Width - 6F;
                    float fX = 3F;
                    float top = (float)fragmentBase.Bottom - 5F;
                    float height = 3F;
                    float left = (float)fragmentBase.X + fX;
                    float width = fW;
                    float wkfc = width / sumFragment;
                    Color[] colors = new Color[] { Color.Red, Color.LightCoral, Color.LightGreen, Color.Yellow };
                    int colori = 0;
                    foreach (float fragment in args.DataElement.Fragments)
                    {
                        float w = fragment * wkfc;
                        RectangleF fragmentOne = new RectangleF(left, top, w, height);
                        args.InnerShapeList.Add(new GraphElementPainterArgs.InnerShapeCls(Rectangle.Truncate(fragmentOne), colors[colori]));
                        left += w;
                        if ((++colori) >= colors.Length)
                            colori = 0;
                    }
                }
            }

            // Okraje pozadí:
            args.BackLineRunSystem = true;
            args.BackSidePenColor = Color.Black;
            args.BackLineWidth = 1;

            // Popisek:
            args.CaptionRunSystem = true;
            args.CaptionColor = this._PaintElementGetCaptionColor(args, Color.Black);

			// Kreslení Image:
			this._PaintElementPrepareImage(args);
		}
        /// <summary>
        /// Příprava pro kreslení elementu grafu Gantt, tvar elementu Hexagon
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPrepareSingleTaskHexagon(GraphElementPainterArgs args)
        {
            // Vlastní prostor reprezentace grafu:
			args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Hexagon vykreslím pouze pro kladnou šířku:
			Rectangle detailArea = args.DetailArea;
            if (detailArea.Width > 0)
            {
                // Pozadí:
                args.BackGroundRunSystem = true;
                detailArea.Height = detailArea.Height - 1;

                // Hexagon vykreslím v závislosti na aktuální šířce prostoru:
                float fW = 0F;
                float fX = 0F;
                if (detailArea.Width <= 3)
                {	// Do 3 pixelů je to obdélník:
                    args.BackGroundRectangle = detailArea;
                }
                else
                {	// Nad 3 pixely si obrazec spočítám:
                    float dX = ((float)detailArea.Width - 2F) / 2F;
                    float dY = dX * 3F;
                    float dH = ((float)detailArea.Height) / 2F;
                    if (dY < dH)
                    {	// Obrazec má vlevo a vpravo tupý nos:
                        int iX = (int)dX;
                        int iY = (int)(Math.Round(dY, 0));
                        args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X + iX, detailArea.Y),
							new Point(detailArea.Right - iX, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY),
							new Point(detailArea.Right, detailArea.Bottom - iY),
							new Point(detailArea.Right - iX, detailArea.Bottom),
							new Point(detailArea.X + iX, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Bottom - iY),
							new Point(detailArea.X, detailArea.Y + iY),
							new Point(detailArea.X + iX, detailArea.Y) };
                    }
                    else
                    {	// Obrazec má vlevo a vpravo ostrou špičku:
                        dY = dH;
                        dX = dY / 3F;
                        int iX = (int)dX;
                        int iY = (int)(Math.Round(dY, 0));
                        args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X + iX, detailArea.Y), 
							new Point(detailArea.Right - iX, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY), 
							new Point(detailArea.Right - iX, detailArea.Bottom), 
							new Point(detailArea.X + iX, detailArea.Bottom), 
							new Point(detailArea.X, detailArea.Y + iY), 
							new Point(detailArea.X + iX, detailArea.Y) };
                    }
                    fX = dX + 2F;
                    fW = (float)detailArea.Width - 2 * fX;
                }

                // Výplň podle sumáře časů:
                bool showFragment = (args.ElementState == GraphElementState.OnMouse || args.ElementState == GraphElementState.Selected || args.ElementState == GraphElementState.Active);
                if (showFragment && detailArea.Width > 7 && args.DataElement.Fragments != null)
                {
                    float sumFragment = 0F;
                    foreach (float fragment in args.DataElement.Fragments)
                        sumFragment += fragment;
                    if (sumFragment > 0F)
                    {
                        Rectangle fragmentBase = detailArea;
                        float top = (float)fragmentBase.Bottom - 5F;
                        float height = 3F;
                        float left = (float)fragmentBase.X + fX;
                        float width = fW;
                        float wkfc = width / sumFragment;
                        Color[] colors = new Color[] { Color.Red, Color.LightCoral, Color.LightGreen, Color.Yellow };
                        int colori = 0;
                        foreach (float fragment in args.DataElement.Fragments)
                        {
                            float w = fragment * wkfc;
                            RectangleF fragmentOne = new RectangleF(left, top, w, height);
                            args.InnerShapeList.Add(new GraphElementPainterArgs.InnerShapeCls(Rectangle.Truncate(fragmentOne), colors[colori]));
                            left += w;
                            if ((++colori) >= colors.Length)
                                colori = 0;
                        }
                    }
                }

                // Okraje pozadí:
                args.BackLineSetSystem(true);

                // Popisek:
                args.CaptionRunSystem = true;
                args.CaptionColor = this._PaintElementGetCaptionColor(args, Color.Black);

				// Kreslení Image:
				this._PaintElementPrepareImage(args);
            }
        }
        /// <summary>
        /// Vrátí barvu písma tak, aby bylo viditelné na aktuálním pozadí
        /// </summary>
        /// <param name="args"></param>
        /// <param name="color"></param>
        /// <returns></returns>
        private Color _PaintElementGetCaptionColor(GraphElementPainterArgs args, Color color)
        {
            Color fontColor = args.DataElement.FontColor;
            return (!fontColor.IsEmpty ? fontColor : color);
        }
        /// <summary>
        /// Příprava pro kreslení elementu grafu Gantt, tvar elementu RightTriangle
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPrepareSingleTaskRightTriangle(GraphElementPainterArgs args)
        {
            // Vstupní konstanty, definují tvar trojúhelníku:
            decimal widthRatio = 0.35M;        // Poměrná šířka trojúhelníku vzhledem k výšce
            decimal rightRatio = 0.65M;        // Poměr šířky trojúhelníku napravo od času End, vzhledem k šířce trojúhelníku (Height * widthRatio)

            // RightTriangle vykreslím jak pro kladnou, tak pro nulovou (i zápornou) šířku:
            Rectangle detailArea = args.DefaultDetailAreaElement;     // Vypočítat prostor pro detail
            detailArea.Height = detailArea.Height - 1;
            int iY = detailArea.Height / 2;                           // Polovina výšky 
            decimal tW = widthRatio * ((decimal)detailArea.Height);   // Šířka trojúhelníku = podle koeficientu
            decimal tR = tW * rightRatio;                             // Přesah trojúhelníku doprava od času End = podle koeficientu
            int iX = (int)(Math.Round(tW, 0));                        // Šířka trojúhelníku = int (v pixelech)
            int triaRight = (int)(Math.Round(tR, 0));                 // Přesah doprava přes okraj času konce = int (v pixelech)
            int elementRight = detailArea.Right + triaRight;          // Pozice Right trianglu = elementu
            int triaLeft = elementRight - iX;                         // Pozice levého pixelu trianglu, může / nemusí být uvnitř detailArea
            bool isTriangle = (triaLeft <= detailArea.X);             // true = je to trojúhelník, když triangl.Left <= element.Left
            detailArea.X = (isTriangle ? triaLeft : detailArea.Left); // Pozice levého pixelu elementu (to víc vlevo: detail / triangl)
            detailArea.Width = elementRight - detailArea.X;

            // Prostor pro reprezentaci grafu : upravím výchozí prostor podle zvětšených rozměrů elementu (detailArea):
            args.DetailArea = detailArea;
            args.BrushArea = _PaintElementWideRectangle(args.RowGraphArea, detailArea);                  // Prostor štětce = podle prostoru řádku, rozšířený
            args.VisualRectangle = _PaintElementWideRectangle(args.DefaultVisualRectangle, detailArea);  // Vizuální prostor je defaultní, rozšířený

            // Pozadí:
            args.BackGroundRunSystem = true;
            detailArea.Height = detailArea.Height - 1;

            // Element vykreslím buď jako trojúhelník nebo pětiúhelník (prasátko s hlavičkou doprava)
            if (isTriangle)
            {	// Trojúhelník:
                args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY),
							new Point(detailArea.X, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Y) };
            }
            else
            {	// Prasátko:
                args.BackGroundPolygon = new Point[] { 
							new Point(detailArea.X, detailArea.Y),
							new Point(detailArea.Right - iX, detailArea.Y),
							new Point(detailArea.Right, detailArea.Y + iY),
							new Point(detailArea.Right - iX, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Bottom),
							new Point(detailArea.X, detailArea.Y) };
            }

            // Výplň podle sumáře časů:
            bool showFragment = (args.ElementState == GraphElementState.OnMouse || args.ElementState == GraphElementState.Selected || args.ElementState == GraphElementState.Active);
            if (showFragment && detailArea.Width > (iX + 8) && args.DataElement.Fragments != null)
            {
                float sumFragment = 0F;
                foreach (float fragment in args.DataElement.Fragments)
                    sumFragment += fragment;
                if (sumFragment > 0F)
                {
                    Rectangle fragmentBase = detailArea;
                    float top = (float)fragmentBase.Bottom - 5F;
                    float height = 3F;
                    float left = (float)fragmentBase.X + 2;
                    float width = detailArea.Width - iX - 2;
                    float wkfc = width / sumFragment;
                    Color[] colors = new Color[] { Color.Red, Color.LightCoral, Color.LightGreen, Color.Yellow };
                    int colori = 0;
                    foreach (float fragment in args.DataElement.Fragments)
                    {
                        float w = fragment * wkfc;
                        RectangleF fragmentOne = new RectangleF(left, top, w, height);
                        args.InnerShapeList.Add(new GraphElementPainterArgs.InnerShapeCls(Rectangle.Truncate(fragmentOne), colors[colori]));
                        left += w;
                        if ((++colori) >= colors.Length)
                            colori = 0;
                    }
                }
            }

            // Okraje pozadí:
            args.BackLineSetSystem(true);

            // Popisek:
            args.CaptionRunSystem = (detailArea.Width > 18);
            args.CaptionColor = this._PaintElementGetCaptionColor(args, Color.Black);

			// Kreslení Image:
			this._PaintElementPrepareImage(args);
		}
        /// <summary>
        /// Příprava pro kreslení elementu grafu CapacityUtilization
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPreparePercentage(GraphElementPainterArgs args)
        {
            // Vlastní prostor reprezentace grafu, základna pro štětec, vizuální prostor:
            args.DetailArea = args.DefaultDetailAreaBack;            // Vypočítat prostor pro detail
            args.BrushArea = args.RowGraphArea;                      // Prostor štětce = podle prostoru řádku
            args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

            // Vykreslení pozadí:
            args.BackGroundRunSystem = true;
            args.BackGroundRectangle = args.DetailArea;              // Prostor pro výplň
            args.BackGroundColor = (!args.DataElement.BackColor.IsEmpty ? args.DataElement.BackColor : Color.FromArgb(216, 240, 255));

            // Vykreslení CapacityUtilization je jen v příslušném grafu:
            if (args.GraphMode == RowGraphMode.Percentage)
            {
                args.VisualRectangle = args.DetailArea;              // V tomto prostoru se aktivuje ToolTip

                args.UtilizationRunSystem = true;
                args.UtilizationRectangle = args.DefaultDetailAreaElement;

                // Vykreslení horní linky:
				this._PaintElementPrepareTopLine(args, args.UtilizationRectangle, true);
            }

            // Boční okraje:
            args.BackSideRunSystem = true;
            args.BackSidePenColor = Color.DarkGreen;
            args.BackSideMinElementWidth = 30;

			// Kreslení Image:
			this._PaintElementPrepareImage(args);
		}
        /// <summary>
        /// Příprava pro kreslení elementu grafu TaskLink
        /// </summary>
        /// <param name="args"></param>
        private void _PaintElementPrepareMultiTask(GraphElementPainterArgs args)
        {
            // Vlastní prostor reprezentace grafu:
            args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.DetailArea;                        // Prostor štětce = podle prostoru řádku
            args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

            // Pokud má element kladný čas, anebo (když jej má nulový) není nastaven příznak "Nekreslit Rectangle pro elementy s nulovou šířkou), zadáme ke kreslení BackGround:
            if (args.DataElement.TimeRange.Seconds > 0D || !args.DataElement.HideZeroWidthElementRectangle)
            {
                bool isUncertain = this._PaintElementPrepareMultiTaskUncertain(args);   // Pokud je element nejistý, zkusí jej tak vykreslit. Když vrátí false, má se element kreslit standardně.
                if (!isUncertain)
                {   // Docela běžný element, jehož oba časy Begin i End jsou jisté:
                    // Pozadí:
                    args.BackGroundRunSystem = true;
                    args.BackGroundRectangle = args.DetailArea;
                    // args.BackGroundColor = Color.Beige;                   // Pokud bych tady definoval barvu, bude použita ona. Pokud nechám Empty, bude použita paleta.

                    // Okraje pozadí:
                    args.BackLineSetSystem(true);
                }
            }

            // Pokud jde o element v řádku, kde jsou použity fragmenty, pak element vykreslím poněkud lépe:
            if (args.RowContainFragments)
            {
                int minDim = 5;
                Rectangle back = args.BackGroundRectangle;
                Point lt = new Point(back.X, back.Y);                  // levý horní roh
                Point rt = new Point(back.Right - 1, back.Y);          // pravý horní roh
                Point rb = new Point(back.Right - 1, back.Bottom - 1); // pravý dolní roh
                Point lb = new Point(back.X, back.Bottom - 1);         // levý dolní roh
                if (args.BackGroundRectangle.Width >= minDim && args.BackGroundRectangle.Height >= minDim)
                {	// Při velikosti 4px a větší vykreslím element se zkosenými hranami
                    // Připravím okraj oblasti, kde hrany budou zkosené o 1 pixel:
                    // Podle BackGroundPolygon se vykreslí výplň:
                    args.BackGroundPolygon = new Point[] {
						new Point(lt.X + 1, lt.Y),    // 0
						new Point(rt.X - 1, rt.Y),    // 1
						new Point(rt.X, rt.Y + 1),    // 2
						new Point(rb.X, rb.Y - 1),    // 3
						new Point(rb.X - 1, rb.Y),    // 4
						new Point(lb.X + 1, lb.Y),    // 5
						new Point(lb.X, lb.Y - 1),    // 6
						new Point(lt.X, lt.Y + 1),    // 7
						new Point(lt.X + 1, lt.Y) };  // 8
                    args.BackGroundRectangle = Rectangle.Empty;

                    // Totéž pole rozdělím na dva segmenty A a B, a vykreslím jeho obrysy dvěma barvami (A, B - viz níže, společné pro obě varianty):
                    // Polygony A a B kreslí jen okraje (DrawLine), a nespojuje se automaticky první s posledním bodem (to by udělal DrawPolygon):
                    args.BackGroundPolygonLineA = new Point[] {
						args.BackGroundPolygon[6],
						args.BackGroundPolygon[7],
						args.BackGroundPolygon[8],
						args.BackGroundPolygon[0],
						args.BackGroundPolygon[1],
						args.BackGroundPolygon[2] };

                    args.BackGroundPolygonLineB = new Point[] {
						args.BackGroundPolygon[2],
						args.BackGroundPolygon[3],
						args.BackGroundPolygon[4],
						args.BackGroundPolygon[5],
						args.BackGroundPolygon[6] };
                }
                else
                {	// Při velikosti pod 4px sice nebudou zkosené hrany, ale bude použit 3D rámeček:
                    args.BackGroundPolygonLineA = new Point[] { lb, lt, rt };
                    args.BackGroundPolygonLineB = new Point[] { rt, rb, lb };
                }
                // Barva rámečku: A=světlá (levá a horní hrana), B=tmavá (pravá a dolní hrana):
                args.BackLineAColor = Color.FromArgb(236, 236, 216);
                args.BackLineBColor = Color.FromArgb(64, 64, 96);
            }

            // Popisek (=text uvnitř elementu) kreslit jen v aktivním elementu, anebo když se má kreslit vždy:
            if (args.ElementState == GraphElementState.OnMouse ||
                args.ElementState == GraphElementState.Selected ||
                args.ElementState == GraphElementState.InEditor ||
                args.ElementState == GraphElementState.Active ||
                args.DataElement.CaptionShowAllways)
            {
                args.CaptionRunSystem = true;
                args.CaptionColor = this._PaintElementGetCaptionColor(args, Color.Black);
            }

			// Kreslení Image:
			this._PaintElementPrepareImage(args);
		}
        /// <summary>
        /// Příprava pro kreslení elementu grafu TaskLink, jehož Begin nebo End jsou nejisté
        /// </summary>
        /// <param name="args"></param>
        private bool _PaintElementPrepareMultiTaskUncertain(GraphElementPainterArgs args)
        {
            bool beginIsUncertain = args.DataElement.BeginIsUncertain;
            bool endIsUncertain = args.DataElement.EndIsUncertain;
            if (!(beginIsUncertain || endIsUncertain))
                return false;                                  // Element je celý jistý, vrátím false a vykreslí se standardně.

            Rectangle detailArea = args.DetailArea;            // Prostor elementu, do něhož kreslíme
            int dx = detailArea.Width / 6;                     // Prostor vlevo / vpravo, v němž vykreslím nejistotu
            int mx = detailArea.Height / 2;                    // Největší velikost prostoru nejistoty
            if (dx > mx) dx = mx;
            if (dx <= 1)
                // Element je příliš úzký na takové vykreslení: vrátím false, a element se vykreslí standardně:
                return false;
            
            // Element je nejistý, a lze jej tak i vykreslit:
            int dy2 = detailArea.Height / 2;                    // Začínám chystat podklady pro grafiku: polovina výšky
            int dy4 = detailArea.Height / 4;
            int dx1 = dx * 2 / 3;
            int dx3 = dx / 3;
            int dx4 = dx / 4;

            // Připravíme si pole bodů, které budou tvořit okraj elementu:
            List<Point> path = new List<Point>();

            int x = detailArea.X;
            int y = detailArea.Y;
            int r = detailArea.Right;
            int b = detailArea.Bottom;

            bool zub = false;
            bool con = true;
            // Begin:
            if (beginIsUncertain)
            {
                if (zub)
                {   // Dvojitý zub (písmeno W otočené doleva)
                    path.Add(new Point(x + dx, b));
                    path.Add(new Point(x, b - dy4));
                    path.Add(new Point(x + dx1, y + dy2));
                    path.Add(new Point(x, y + dy4));
                    path.Add(new Point(x + dx, y));
                }
                else if (con)
                {   // Zkosený levý horní roh:
                    path.Add(new Point(x, b));
                    path.Add(new Point(x, b - dy4));
                    path.Add(new Point(x + dx4, y + dy2));
                    path.Add(new Point(x + dx3, y + dy4));
                    path.Add(new Point(x + dx, y));
                }
                else
                {   // Oblouk doleva:
                    path.Add(new Point(x + dx, b));
                    path.Add(new Point(x + dx3, b - dy4));
                    path.Add(new Point(x, y + dy2));
                    path.Add(new Point(x + dx3, y + dy4));
                    path.Add(new Point(x + dx, y));
                }
            }
            else
            {
                path.Add(new Point(x, b));
                path.Add(new Point(x, y));
            }

            // End:
            if (endIsUncertain)
            {   // Dvojitý zub (písmeno W otočené doprava)
                if (zub)
                {
                    path.Add(new Point(r - dx, y));
                    path.Add(new Point(r, y + dy4));
                    path.Add(new Point(r - dx1, y + dy2));
                    path.Add(new Point(r, b - dy4));
                    path.Add(new Point(r - dx, b));
                }
                else if (con)
                {   // Zkosený pravý dolní roh:
                    path.Add(new Point(r, y));
                    path.Add(new Point(r, y + dy4));
                    path.Add(new Point(r - dx4, y + dy2));
                    path.Add(new Point(r - dx3, b - dy4));
                    path.Add(new Point(r - dx, b));
                }
                else
                {   // Oblouk doprava:
                    path.Add(new Point(r - dx, y));
                    path.Add(new Point(r - dx3, y + dy4));
                    path.Add(new Point(r, y + dy2));
                    path.Add(new Point(r - dx3, b - dy4));
                    path.Add(new Point(r - dx, b));
                }
            }
            else
            {
                path.Add(new Point(r, y));
                path.Add(new Point(r, b));
            }

            // Close path:
            path.Add(path[0]);

            // Kreslit back:
            args.BackGroundRunSystem = true;
            args.BackGroundPolygon = path.ToArray();

            // Okraje pozadí:
            args.BackLineSetSystem(false);

            return true;
        }
		/// <summary>
		/// Příprava pro kreslení elementu grafu BarGraph
		/// </summary>
		/// <param name="args"></param>
		/// <returns></returns>
		private void _PaintElementPrepareBarGraph(GraphElementPainterArgs args)
		{
			// Vlastní prostor reprezentace grafu:
            args.DetailArea = args.DefaultDetailAreaElement;         // Vypočítat prostor pro detail
			args.BrushArea = args.DetailArea;                        // Prostor štětce = podle prostoru řádku
			args.VisualRectangle = args.DefaultVisualRectangle;      // Vizuální prostor je defaultní

			// Pokud má element kladný čas, anebo (když jej má nulový) není nastaven příznak "Nekreslit Rectangle pro elementy s nulovou šířkou), zadáme ke kreslení BackGround:
			if (args.DataElement.TimeRange.Seconds > 0D || !args.DataElement.HideZeroWidthElementRectangle)
			{
				// Pozadí:
				args.BackGroundRunSystem = true;
				args.BackGroundRectangle = args.DetailArea;
				// args.BackGroundColor = Color.Beige;                   // Pokud bych tady definoval barvu, bude použita ona. Pokud nechám Empty, bude použita paleta.

				// Okraje pozadí:

                // Vykreslení horní linky:
				this._PaintElementPrepareTopLine(args, args.DefaultDetailAreaElement, false);
			}
			
			// Popisek (=text uvnitř elementu) kreslit jen v aktivním elementu, anebo když se má kreslit vždy:
			if (args.ElementState == GraphElementState.OnMouse ||
				args.ElementState == GraphElementState.Selected ||
				args.ElementState == GraphElementState.InEditor ||
				args.ElementState == GraphElementState.Active ||
				args.DataElement.CaptionShowAllways ||
                args.DetailArea.Width > 45)
			{
				args.CaptionRunSystem = true;
                args.CaptionColor = this._PaintElementGetCaptionColor(args, Color.Black);
			}

			// Kreslení Image:
			this._PaintElementPrepareImage(args);
		}
		/// <summary>
		/// Do argumentu args zadá povely k vykreslení čáry TopLine
		/// </summary>
		/// <param name="args">grafická data</param>
		/// <param name="utilRec">Obdélník, jehož horní strana se rámuje</param>
		/// <param name="withStart">Včetně startu z bodu 0/0 řádku</param>
		private void _PaintElementPrepareTopLine(GraphElementPainterArgs args, Rectangle utilRec, bool withStart)
		{
			args.TopLineRunSystem = true;
			List<Point> polygon = new List<Point>();
			if (args.LastPoint.IsEmpty)
			{	// Čára ještě nezačala, začneme ji na začátku našeho řádku a dojedeme k naší X souřadnici:
				if (withStart)
				{
					polygon.Add(new Point(args.RowGraphArea.X, utilRec.Bottom));
					polygon.Add(new Point(utilRec.X, utilRec.Bottom));
				}
			}
			else if (args.LastPoint.X < utilRec.X)
			{	// Čára už někde běží, ale skončila vlevo od našeho levého okraje:
				polygon.Add(args.LastPoint);                                 // Navážu tam, kde skončila
				polygon.Add(new Point(args.LastPoint.X, utilRec.Bottom));    // Sjedu na jejím čase k nule
				polygon.Add(new Point(utilRec.X, utilRec.Bottom));           //  a dojedu na můj čas počátku v nulové souřadnici
			}
			else if (args.LastPoint.X == utilRec.X)
			{	// Čára skončila v tom čase, kdy já začínám:
				polygon.Add(args.LastPoint);                                 // Navážu tam, kde skončila
			}
			// Můj levý horní a pravý horní bod:
			polygon.Add(new Point(utilRec.X, utilRec.Y));
			polygon.Add(new Point(utilRec.Right, utilRec.Y));

			args.TopLinePolygon = polygon.ToArray();
			args.LastPoint = polygon[polygon.Count - 1];
		}
		/// <summary>
		/// Vrátí kombinaci defaultního prostoru (Y, Height) a rozšířeného prostoru (X, Width)
		/// </summary>
		/// <param name="defArea"></param>
		/// <param name="wideArea"></param>
		/// <returns></returns>
		private Rectangle _PaintElementWideRectangle(Rectangle defArea, Rectangle wideArea)
		{
			return new Rectangle(wideArea.X, defArea.Y, wideArea.Width, defArea.Height);
		}
		/// <summary>
		/// Příprava pro kreslení obrázku
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementPrepareImage(GraphElementPainterArgs args)
		{
			if (args.DataElement.ElementImage == null)
				return;

			args.ImageRunSystem = true;
			args.Image = args.DataElement.ElementImage;
			// Určit umístění obrázku - vzhledem k elementu:
			Rectangle elementArea = args.DetailArea;
			if (elementArea.IsEmpty)
				elementArea = args.BrushArea;
			if (elementArea.IsEmpty)
				elementArea = args.VisualRectangle;
			if (elementArea.IsEmpty)
				elementArea = args.DefaultDetailAreaElement;

			Point elementPivot = elementArea.PivotPoint(args.DataElement.ImagePivotElementPoint);   // Vrátí pivot point pro celý element

			Size imageSize = args.Image.Size;
			Rectangle imageArea = new Rectangle(0, 0, imageSize.Width, imageSize.Height);
			Point imagePivot = imageArea.PivotPoint(args.DataElement.ImagePivotImagePoint);         // Pivot point pro Image

			imageArea.X = elementPivot.X - imagePivot.X;
			imageArea.Y = elementPivot.Y - imagePivot.Y;

			args.ImageArea = imageArea;

			// Pokud by měl obrázek větší souřadnice ve směru X než args.DetailArea, pak musím args.DetailArea zvětšit:
			//  (to proto, že args.DetailArea se stane základem pro interaktivní mapu elementů řádku):
			if (imageArea.X < args.DetailArea.X)
				args.DetailArea.X = imageArea.X;
			if (imageArea.Right > args.DetailArea.Right)
				args.DetailArea.Width = imageArea.Right - args.DetailArea.X;
		}
		#endregion
		#region KRESLENÍ NA ZÁKLADĚ DAT PŘIPRAVENÝCH PAINTEREM IGraphElementPainter (ZDE SE KRESLÍ)
		/// <summary>
		/// Dodatkové vykreslení elementu poté, kdy jeho kreslení zahájil painter.
		/// Tato metoda fyzicky vylreslí to, co painter nadeklaroval (data + požadavek na vykreslení).
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefault(GraphElementPainterArgs args)
		{
			// Spodní rámeček:
			if (args.OuterLineRunSystem)
				this._PaintElementDefaultLineOuter(args);

			// Painter chce vykreslit background:
			if (args.BackGroundRunSystem)
				this._PaintElementDefaultFillBack(args);

			// Painter chce orámovat celý prostor Background:
			if (args.BackLineRunSystem)
				this._PaintElementDefaultLineBack(args);
			// Painter chce orámovat vlevo a vpravo prostor Background:
			if (args.BackSideRunSystem)
				this._PaintElementDefaultLineSide(args);

			// Painter chce vykreslit pozadí Utilization:
			if (args.UtilizationRunSystem)
				this._PaintElementDefaultUtilization(args);

			// Painter chce vykreslit vnitřní tvary:
			if (args.InnerShapeRunSystem)
				this._PaintElementDefaultInnerShape(args);

			// Painter chce vykreslit linku TopLine (linkový graf nahoře):
			if (args.TopLineRunSystem)
				this._PaintElementDefaultTopLine(args);

			// Painter chce vykreslit obrazec FillRatio:


			// Painter chce vypsat text do elementu:
			if (args.CaptionRunSystem)
				this._PaintElementDefaultDrawCaption(args);

			// Painter chce vykreslit Image?
			if (args.ImageRunSystem)
				this._PaintElementDefaultDrawImage(args);
		}
		/// <summary>
		/// Vykreslí spodní orámování pozadí elementu
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultLineOuter(GraphElementPainterArgs args)
		{
			Pen backPen = args.OuterLinePen;
			bool backPenDispose = args.OuterLinePenDispose;
			if (backPen == null && !args.OuterLineColor.IsEmpty)
			{
				this._ColorFixedPen.Color = args.OuterLineColor;
				this._ColorFixedPen.Width = (args.OuterLineWidth > 0F ? args.OuterLineWidth : 1F);
				backPen = this._ColorFixedPen;
				backPenDispose = false;
			}
			if (backPen == null)
			{
				backPen = this._PaintElementDefaultBackPen(args);
				backPenDispose = false;
			}
			if (backPen == null) return;

			if (args.BackGroundPolygon != null)
			{
				SmoothingMode osm = args.PaintArgs.Graphics.SmoothingMode;
				args.PaintArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
				args.PaintArgs.Graphics.DrawPolygon(backPen, args.BackGroundPolygon);
				args.PaintArgs.Graphics.SmoothingMode = osm;
			}
			else
			{
				Rectangle backR = args.BackGroundRectangle;
				if (backR.IsEmpty)
					backR = args.DefaultDetailAreaBack;
				args.PaintArgs.Graphics.DrawRectangle(backPen, backR);
			}
            this._PaintDisposePen(backPen, backPenDispose);
			backPen = null;
		}
		/// <summary>
		/// Vyplní pozadí elementu.
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultFillBack(GraphElementPainterArgs args)
		{
			Brush backBrush = args.BackGroundBrush;
			bool backBrushDispose = args.BackGroundBrushDispose;
			if (backBrush == null && !args.BackGroundColor.IsEmpty)
			{
				this._ColorSolidBrush.Color = args.BackGroundColor;
				backBrush = this._ColorSolidBrush;
				backBrushDispose = false;
			}
			if (backBrush == null)
			{
                backBrush = this._PaintElementDefaultBackBrush(args, out backBrushDispose);
			}
			if (backBrush == null) return;

			if (args.BackGroundPolygon != null)
			{
				args.PaintArgs.Graphics.FillPolygon(backBrush, args.BackGroundPolygon);
			}
			else
			{
				Rectangle backR = args.BackGroundRectangle;
				if (backR.IsEmpty)
					backR = args.DefaultDetailAreaBack;
				args.PaintArgs.Graphics.FillRectangle(backBrush, backR);
			}
            this._PaintDisposeBrush(backBrush, backBrushDispose);
			backBrush = null;
		}
		/// <summary>
		/// Orámuje pozadí elementu
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultLineBack(GraphElementPainterArgs args)
		{
			bool isDrawed = false;
			if (args.BackGroundPolygonLineA != null)
			{
				this._PaintElementDefaultLineBackA(args);
				isDrawed = true;
			}
			if (args.BackGroundPolygonLineB != null)
			{
				this._PaintElementDefaultLineBackB(args);
				isDrawed = true;
			}
			if (!isDrawed)
				this._PaintElementDefaultLineBackS(args);
		}
		/// <summary>
		/// Vykreslí linky okolo pozadí args.BackGroundPolygonLineA
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultLineBackA(GraphElementPainterArgs args)
		{
			if (args.BackGroundPolygonLineA != null)
			{
				bool linePenDispose;
				Pen linePen = this._PaintElementGetPen(args.BackLinePenA, args.BackLinePenADispose, args.BackLineAColor, args.BackLineAWidth, out linePenDispose);
				if (linePen == null) return;

				SmoothingMode osm = args.PaintArgs.Graphics.SmoothingMode;
				args.PaintArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
				args.PaintArgs.Graphics.DrawLines(linePen, args.BackGroundPolygonLineA);
				args.PaintArgs.Graphics.SmoothingMode = osm;

                this._PaintDisposePen(linePen, linePenDispose);
			}
		}
		/// <summary>
		/// Vykreslí linky okolo pozadí args.BackGroundPolygonLineB
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultLineBackB(GraphElementPainterArgs args)
		{
			if (args.BackGroundPolygonLineB != null)
			{
				bool linePenDispose;
				Pen linePen = this._PaintElementGetPen(args.BackLinePenB, args.BackLinePenBDispose, args.BackLineBColor, args.BackLineBWidth, out linePenDispose);
				if (linePen == null) return;

				SmoothingMode osm = args.PaintArgs.Graphics.SmoothingMode;
				args.PaintArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
				args.PaintArgs.Graphics.DrawLines(linePen, args.BackGroundPolygonLineB);
				args.PaintArgs.Graphics.SmoothingMode = osm;

                this._PaintDisposePen(linePen, linePenDispose);
            }
		}
		/// <summary>
		/// Vykreslí linky okolo pozadí args.BackGroundPolygon nebo args.BackGroundRectangle
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultLineBackS(GraphElementPainterArgs args)
		{
			bool linePenDispose;
			Pen linePen = _PaintElementGetPen(args.BackLinePen, args.BackLinePenDispose, args.BackLineColor, args.BackLineWidth, out linePenDispose);
			if (linePen == null) return;

			if (args.BackGroundPolygon != null)
			{
				SmoothingMode osm = args.PaintArgs.Graphics.SmoothingMode;
				args.PaintArgs.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
				args.PaintArgs.Graphics.DrawPolygon(linePen, args.BackGroundPolygon);
				args.PaintArgs.Graphics.SmoothingMode = osm;
			}
			else
			{
				Rectangle backR = args.BackGroundRectangle;
				if (backR.IsEmpty)
					backR = args.DefaultDetailAreaBack;
				args.PaintArgs.Graphics.DrawRectangle(linePen, backR);
			}

            this._PaintDisposePen(linePen, linePenDispose);
		}
		/// <summary>
		/// Orámuje vlevo a vpravo prostor background. Nemůže vycházet z polygonu.
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultLineSide(GraphElementPainterArgs args)
		{
			Rectangle backR = args.BackGroundRectangle;
			if (backR.IsEmpty)
				backR = args.DefaultDetailAreaBack;
			if (backR.Width >= args.BackSideMinElementWidth)
			{
				Pen sidePen = _PaintElementGetPen(args.BackSidePenColor, args.BackSidePenWidth);
				if (sidePen != null)
				{
					Rectangle rowGraphArea = args.RowGraphArea;
					if (backR.X >= rowGraphArea.X && backR.X < rowGraphArea.Right)
						args.PaintArgs.Graphics.DrawLine(sidePen, backR.X, backR.Y, backR.X, backR.Bottom - 1);
					if (backR.Right >= rowGraphArea.X && backR.Right < rowGraphArea.Right)
						args.PaintArgs.Graphics.DrawLine(sidePen, backR.Right - args.BackSidePenWidth + 1, backR.Y, backR.Right - args.BackSidePenWidth + 1, backR.Bottom - 1);
				}
			}
		}
		/// <summary>
		/// Vykreslí pozadí Utilization
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultUtilization(GraphElementPainterArgs args)
		{
			Brush utilBrush = args.UtilizationBrush;
			bool utilBrushDispose = args.UtilizationBrushDispose;
			if (utilBrush == null && !args.UtilizationColor.IsEmpty)
			{
				this._ColorSolidBrush.Color = args.UtilizationColor;
				utilBrush = this._ColorSolidBrush;
				utilBrushDispose = false;
			}
			if (utilBrush == null)
			{
				this._ColorSolidBrush.Color = args.DataElement.BackColor;
				utilBrush = this._ColorSolidBrush;
				utilBrushDispose = false;
			}
			if (utilBrush == null) return;

			if (args.UtilizationPolygon != null)
			{
				args.PaintArgs.Graphics.FillPolygon(utilBrush, args.UtilizationPolygon);
			}
			else
			{
				Rectangle backR = args.UtilizationRectangle;
				if (backR.IsEmpty)
					backR = args.DefaultDetailAreaElement;
				args.PaintArgs.Graphics.FillRectangle(utilBrush, backR);
			}

            this._PaintDisposeBrush(utilBrush, utilBrushDispose);
		}
		/// <summary>
		/// Vykreslí vnitřní tvary, definované v args
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultInnerShape(GraphElementPainterArgs args)
		{
			foreach (GraphElementPainterArgs.InnerShapeCls innerShape in args.InnerShapeList)
			{
				if (innerShape.InnerRectangle.IsEmpty && innerShape.InnerPolygon == null)
					continue;

                if (innerShape.InnerBackBrush != null)
                {
                    if (!innerShape.InnerRectangle.IsEmpty)
                        args.PaintArgs.Graphics.FillRectangle(this._ColorSolidBrush, innerShape.InnerRectangle);
                    else if (innerShape.InnerPolygon != null)
                        args.PaintArgs.Graphics.FillPolygon(this._ColorSolidBrush, innerShape.InnerPolygon);

                    if (innerShape.InnerBackBrushNeedDispose)
                    {
                        innerShape.InnerBackBrush.Dispose();
                        innerShape.InnerBackBrush = null;
                    }
                }

                else if (!innerShape.InnerBackColor.IsEmpty)
				{
					this._ColorSolidBrush.Color = innerShape.InnerBackColor;
					if (!innerShape.InnerRectangle.IsEmpty)
						args.PaintArgs.Graphics.FillRectangle(this._ColorSolidBrush, innerShape.InnerRectangle);
					else if (innerShape.InnerPolygon != null)
						args.PaintArgs.Graphics.FillPolygon(this._ColorSolidBrush, innerShape.InnerPolygon);
				}

				if (!innerShape.InnerLineColor.IsEmpty)
				{
					this._ColorFixedPen.Color = innerShape.InnerLineColor;
					if (!innerShape.InnerRectangle.IsEmpty)
						args.PaintArgs.Graphics.DrawRectangle(this._ColorFixedPen, innerShape.InnerRectangle);
					else if (innerShape.InnerPolygon != null)
						args.PaintArgs.Graphics.DrawPolygon(this._ColorFixedPen, innerShape.InnerPolygon);
				}
			}
		}
		/// <summary>
		/// Vykreslí linku na horním okraji grafu, vyjadřuje poměrné čerpání kapacity, nebo vývoj zásoby
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultTopLine(GraphElementPainterArgs args)
		{
			if (args.TopLinePolygon == null) return;

			Pen linePen = _PaintElementGetPen(Color.Yellow, 2F);

			// args.PaintArgs.Graphics.DrawPolygon(this._ColorFixedPen, args.TopLinePolygon);
			args.PaintArgs.Graphics.DrawLines(linePen, args.TopLinePolygon);
		}
		/// <summary>
		/// Vykreslí text elementu.
		/// </summary>
		private void _PaintElementDefaultDrawCaption(GraphElementPainterArgs args)
		{
			if (args.DataElement == null || args.DetailArea.IsEmpty || args.DetailArea.Width < 10) return;   // Pod 10px šířky nekreslíme.

			// Font:
			Font font = args.CaptionFont;
			bool fontDispose = args.CaptionFontDispose;
			if (font == null)
			{
				font = this._CreateFont(GridGraphPaletteType.ElementCaptionText);
				fontDispose = true;
			}
			if (font == null) return;

			// Štětec, barva:
			Brush brush = args.CaptionBrush;
			bool brushDispose = args.CaptionBrushDispose;
			if (brush == null && !args.CaptionColor.IsEmpty)
			{
				this._ColorSolidBrush.Color = args.CaptionColor;
				brush = this._ColorSolidBrush;
				brushDispose = false;
			}
			if (brush == null)
			{
				brush = this._GetBrush(GridGraphPaletteType.ElementCaptionText);
				brushDispose = false;
			}
            if (brush != null)
            {

                // Vlastní text:
                Rectangle captionArea = args.DefaultCaptionArea;
                string text = args.CaptionText;
                if (String.IsNullOrEmpty(text))
                	// Text zkusím získat z elementu:
                    text = _PaintElementGetElementText(args, font, captionArea);
                if (!String.IsNullOrEmpty(text))
                    // Psaní textu:
                    this._PaintText(args.PaintArgs.Graphics, text, font, brush, captionArea, TextFormatFlags.HorizontalCenter);
            }
            this._PaintDisposeBrush(brush, brushDispose);
            this._PaintDisposeFont(font, fontDispose);
		}
        /// <summary>
        /// Určí text do elementu pro aktuální velikost elementu.
        /// </summary>
        /// <param name="args"></param>
        /// <param name="textArea"></param>
        /// <returns></returns>
        private string _PaintElementGetElementText(GraphElementPainterArgs args, Font font, Rectangle textArea)
        {
            // 1. Zkusím získat sadu textů z IDataElement a z ní si vybrat text, který se pěkně vejde:
            string[] captions = args.DataElement.Captions;
            if (captions != null)
            {
                float maxWidth = textArea.Width - 8;                // Max šířka textu = menší než prostor, pro jistotu
                string result = null;
                foreach (string caption in captions)                // V poli this.Captions jsou texty do elementu v pořadí od nejkratšího po nejdelší.
                {
                    if (String.IsNullOrEmpty(caption)) continue;    // Null neberu
                    if (result == null)
                        result = caption;                           // První zadaný text beru vždy
                    else if (args.PaintArgs.Graphics.MeasureString(caption, font).Width > maxWidth) // Pokud tento text je delší, než se nám vejde, tak skončím (v result je nalezený předchozí = nejdelší použitelný text):
                        break;
                    else
                        result = caption;
                }
                if (result != null)
                    return result;
            }

            // 2. Určím odhad počtu znaků a zeptám se IDataElement jinou cestou:
            float charCount = ((float)textArea.Width) / args.PaintArgs.Graphics.MeasureString("1234567890", font).Width * 10F;
            return args.DataElement.GetCaption(args.RowItem, charCount);
        }
		/// <summary>
		/// Vykreslí obrázek
		/// </summary>
		/// <param name="args"></param>
		private void _PaintElementDefaultDrawImage(GraphElementPainterArgs args)
		{
			if (args.Image == null) return;
			//args.PaintArgs.Graphics.DrawImageUnscaled(args.Image, args.ImageArea);
			args.PaintArgs.Graphics.DrawImage(args.Image, args.ImageArea);
		}
		/// <summary>
		/// Vrací defaultní barvu pro výplň pozadí elementu
		/// </summary>
		/// <param name="args"></param>
		/// <returns></returns>
		private Brush _PaintElementDefaultBackBrush(GraphElementPainterArgs args, out bool brushDispose)
		{
            brushDispose = false;

            // Temp layer vždy vrátí brush jednoduchý (podle stavu Temp elementu: Work / Error):
			if (args.DataElement.ElementLayer == GraphLayerType.ElementTempLayer)
				return this._GetBrush(args.ChartElement.TempElementState == GraphTempElementState.TempError ? GridGraphPaletteType.TempElementError : GridGraphPaletteType.TempElementWork);

            // Pro ostatní záležitosti vytvořím a vrátím brush speciální:
            brushDispose = true;
            return this._CreateBrush(args.BrushArea, args.ElementBackColor, args.ElementGradientType);
		}
		/// <summary>
		/// Vrátí pero podle daných atributů
		/// </summary>
		/// <param name="penColor">Barva pera, použije se pokud není předáno vstupní pero explicitPen. Pokud bude Color.Empty, použije se systémová barva (černá).</param>
		/// <param name="penWidth">Šířka pera, použije se pokud není předáno vstupní pero explicitPen. Default = 1
		/// Pokud bude použito vstupní pero explicitPen, bude sem nastavena hodnota toDispose, jinak bude false.</param>
		/// <returns></returns>
		private Pen _PaintElementGetPen(Color penColor, float penWidth)
		{
			bool penDispose;
			return _PaintElementGetPen(null, false, penColor, penWidth, out penDispose);
		}
		/// <summary>
		/// Vrátí pero podle daných atributů
		/// </summary>
		/// <param name="explicitPen">Vstupní pero, může být null</param>
		/// <param name="toDispose">Požadavek, aby vstupní pero (explicitPen) bylo po použití zlikvidováno (Dispose)</param>
		/// <param name="penColor">Barva pera, použije se pokud není předáno vstupní pero explicitPen. Pokud bude Color.Empty, použije se systémová barva (černá).</param>
		/// <param name="penWidth">Šířka pera, použije se pokud není předáno vstupní pero explicitPen. Default = 1</param>
		/// <param name="penDispose">Out: vrácené pero se má zlikvidovat (Dispose).
		/// Pokud bude použito vstupní pero explicitPen, bude sem nastavena hodnota toDispose, jinak bude false.</param>
		/// <returns></returns>
		private Pen _PaintElementGetPen(Pen explicitPen, bool toDispose, Color penColor, float penWidth, out bool penDispose)
		{
			penDispose = false;
			if (explicitPen != null)
			{
				penDispose = toDispose;
				return explicitPen;
			}

			this._ColorFixedPen.Color = (penColor.IsEmpty ? Color.Black : penColor);
			this._ColorFixedPen.Width = (penWidth > 0F ? penWidth : 1F);
			return this._ColorFixedPen;
		}
		/// <summary>
		/// Vrátí defaultní pero pro orámování pozadí elementu
		/// </summary>
		/// <param name="args"></param>
		/// <returns></returns>
		private Pen _PaintElementDefaultBackPen(GraphElementPainterArgs args)
		{
			return this._GetPen(GridGraphPaletteType.ElementCaptionText);
		}
		/// <summary>
		/// Vrátí příznak stavu elementu, který ovlivní režim zobrazování elementu.
		/// </summary>
		/// <param name="element">Element, jehož modifikaci určujeme.</param>
		/// <returns>Typ palety pro vykreslení elementu.</returns>
		private GraphElementState _ElementDetectState(GridDataElementCls element)
		{
			if (element == null) return GraphElementState.Dead;

			GID elementGId = element.DataElement.GId;
            bool isDead = false;
            bool isSelected = this._SelectedInfo.IsGidSelected(element.GId);
			bool isOnMouse = (elementGId == this._MouseCurrentTarget.ElementGId);
			bool isActive = (elementGId == this._MouseDownStateTarget.ElementGId && ((this._MouseCurrentAction & _MouseActionType.ElementClicked) > 0));
            bool isInEditor = false;

			if (isDead)
				// Element nelze posouvat ani resizovat:
				return GraphElementState.Dead;
			
			if (isActive)
				// Elementem se aktivně pohybuje:
				return GraphElementState.Active;
			else if (isSelected)
				// Element je Selected:
				return GraphElementState.Selected;
			else if (isInEditor)
				// Element je v editoru:
				return GraphElementState.InEditor;
			else if (isOnMouse)
				// Element se nyní nachází pod myší:
				return GraphElementState.OnMouse;
			return GraphElementState.Standart;
			
		}
		/// <summary>
		/// Zjistí, zda je element aktivní (tj. zda je selectovaný), volitelně detekuje stav, zda je element "pod myší".
		/// </summary>
		/// <param name="element"></param>
		/// <returns></returns>
		private bool _ElementDetectActive(GridDataElementCls element, bool detectOnMouse)
		{
			if (element == null) return false;

			GID elementGId = element.DataElement.GId;
            bool isSelected = false;
			bool isOnMouse = (elementGId == this._MouseCurrentTarget.ElementGId);
			bool isActive = (elementGId == this._MouseDownStateTarget.ElementGId && ((this._MouseCurrentAction & _MouseActionType.ElementClicked) > 0));
			return (isSelected || (detectOnMouse && isOnMouse) || isActive);
		}
        /// <summary>
        /// Dispose pera
        /// </summary>
        /// <param name="pen"></param>
        /// <param name="penDispose"></param>
        private void _PaintDisposePen(Pen pen, bool penDispose)
        {
            if (penDispose && pen != null)
                pen.Dispose();
        }
        /// <summary>
        /// Dispose štětce
        /// </summary>
        /// <param name="brush"></param>
        /// <param name="brushDispose"></param>
        private void _PaintDisposeBrush(Brush brush, bool brushDispose)
        {
            if (brushDispose && brush != null)
                brush.Dispose();
        }
        /// <summary>
        /// Dispose fontu
        /// </summary>
        /// <param name="font"></param>
        /// <param name="fontDispose"></param>
        private void _PaintDisposeFont(Font font, bool fontDispose)
        {
            if (fontDispose && font != null)
                font.Dispose();
        }
        #endregion
		#region STATIC SERVIS
        /// <summary>
        /// Konvertor stavu elementu (GraphElementState) na typ gradientu (GraphElementGradientType)
        /// </summary>
        /// <param name="elementState"></param>
        /// <returns></returns>
        internal static GraphElementGradientType GetGradientType(GraphElementState elementState)
        {
            switch (elementState)
            {
                case GraphElementState.Active:
                    return GraphElementGradientType.Active;
                case GraphElementState.Dead:
                    return GraphElementGradientType.Fixed;
                case GraphElementState.InEditor:
                    return GraphElementGradientType.Selected;
                case GraphElementState.OnMouse:
                    return GraphElementGradientType.OnMouse;
                case GraphElementState.Selected:
                    return GraphElementGradientType.Selected;
                case GraphElementState.Standart:
                    return GraphElementGradientType.Standard;
            }
            return GraphElementGradientType.Standard;
		}
		#endregion
	}
	#region CLASS GraphElementPainterArgs : DATA PRO KRESLENÍ ELEMENTU
	/// <summary>
	/// GraphElementPainterArgs : data pro kreslení jednoho elementu
	/// </summary>
    public class GraphElementPainterArgs
	{
		#region KONSTRUKCE
        internal GraphElementPainterArgs(PaintEventArgs paintArgs, GridDataVisualLineCls dataLine, GridDataElementCls element, Rectangle rowGraphArea, Rectangle elementArea, GraphElementState elementState, IDataSource dataSource, Point lastPoint)
        {
            this._PaintArgs = paintArgs;
            this._DataLine = dataLine;
            this._ChartElement = element;
            this._RowGraphArea = rowGraphArea;
            this._ElementArea = elementArea;
            this._ElementState = elementState;
			this._DataSource = dataSource;
		    this.LastPoint = lastPoint;

            this._Reset();
        }
        private void _Reset()
        {
            BackGroundColor = Color.Empty;
            BackLineColor = Color.Empty;
            BackLineWidth = 0F;
            OuterLineColor = Color.Empty;
            OuterLineWidth = 3F;
            UtilizationColor = Color.Empty;
            BackSideMinElementWidth = 25;
            BackSidePenColor = Color.Empty;
            BackSidePenWidth = 1;
            TopLinePenColor = Color.Empty;
            TopLinePenWidth = 0F;
            CaptionColor = Color.Empty;
        }
		private System.Windows.Forms.PaintEventArgs _PaintArgs;
        private GridDataVisualLineCls _DataLine;
        private GridDataElementCls _ChartElement;
		private GraphElementState _ElementState;
		private Rectangle _ElementArea;
		private Rectangle _RowGraphArea;
		private IDataSource _DataSource;
		#endregion
		#region PROPERTY ZÁKLADNÍ + ODVOZENÉ
		/// <summary>
		/// Argument pro podporu kreslení
		/// </summary>
		internal System.Windows.Forms.PaintEventArgs PaintArgs { get { return this._PaintArgs; } }
        /// <summary>
        /// Vizuální řádek
        /// </summary>
        internal GridDataVisualLineCls DataLine { get { return this._DataLine; } }
        /// <summary>
        /// Fyzická podkladová data řádku
        /// </summary>
        internal GridDataRowCls DataRow { get { return this._DataLine.DataRow; } }
        /// <summary>
        /// Fyzická podkladová data řádku
        /// </summary>
        internal IDataRow RowItem { get { return this._DataLine.DataRow.RowItem; } }
        /// <summary>
        /// Vizuální element
        /// </summary>
        internal GridDataElementCls ChartElement { get { return this._ChartElement; } }
        /// <summary>
        /// Fyzická podkladová data elementu
        /// </summary>
        internal IDataElement DataElement { get { return this._ChartElement.DataElement; } }
		/// <summary>
		/// Stav elementu.
		/// </summary>
		internal GraphElementState ElementState { get { return this._ElementState; } }
		/// <summary>
		/// Příznak, že řádek s tímto elementem obsahuje fragmenty
		/// </summary>
		internal bool RowContainFragments { get { return this.DataRow.ContainFragments; } }
        /// <summary>
        /// Prostor řádku
        /// </summary>
        internal Rectangle RowGraphArea { get { return this._RowGraphArea; } }
        /// <summary>
		/// Prostor vyhrazený pro element
		/// </summary>
		internal Rectangle ElementArea { get { return this._ElementArea; } }
		/// <summary>
		/// Out parametr: prostor definující souřadnice štětce (Brush).
		/// Pokud bude třeba vytvořit defaultní štětec, bude vytvořen pro tento prostor.
		/// </summary>
		internal Rectangle BrushArea;
		/// <summary>
		/// Out parametr: prostor elementu, který je vizuálně využitý.
		/// Tento prostor je aktivní (reaguje na myší akce).
		/// </summary>
		internal Rectangle DetailArea;  // Nepředělávat na property !!!    Využívám drobných změn: args.DetailArea.X = ..., a to s property nejde.
		/// <summary>
		/// Ref parametr: poslední pozice. Pro některé typy grafů má význam, když se vykresluje spojitá čára nad elementy.
		/// Například Gantt s využitím kapacit, nebo skladová zásoba, atd.
		/// </summary>
		internal Point LastPoint;
		/// <summary>
		/// Typ grafu v aktuálním řádku
		/// </summary>
		internal RowGraphMode GraphMode { get { return this.RowItem.RowGraph; } }
		/// <summary>
		/// Číslo třídy elementu
		/// </summary>
		internal int ClassNumber { get { return this.DataElement.GId.ClassNumber; } }
		/// <summary>
		/// Vrstva grafu
		/// </summary>
        internal GraphLayerType LayerType { get { return this.DataElement.ElementLayer; } }
		/// <summary>
		/// Typ grafiky elementu
		/// </summary>
        internal GraphElementShapeType ElementShapeType { get { return this.DataElement.ElementShapeType; } }
		/// <summary>
		/// Barva pozadí grafického elementu
		/// </summary>
		internal Color ElementBackColor { get { return this.DataElement.BackColor; } }
        /// <summary>
        /// Obsahuje typ gradientu, který odpovídá stavu elementu this.ElementState
        /// </summary>
        internal GraphElementGradientType ElementGradientType { get { return GridGraphCls.GetGradientType(this.ElementState); } }
		#endregion
		#region PROPERTY GRAFICKÉ = POŽADAVKY A DATA PRO DALŠÍ KRESLENÍ
		/// <summary>Příznak, že painter zajistil vše, a nic defaultního se nebude kreslit</summary>
		internal bool IsAllFinished { get; set; }
		/// <summary>Příznak, že painter chce po vykreslení elementu zavolat svoji metodu PaintAfter(). Pokud je false (default), metoda se nevolá.</summary>
		internal bool CallPaintAfter { get; set; }

		/// <summary>Příznak, že painter definoval Rectangle BackGroundRectangle anebo polygon Point[] BackGroundPolygon, a je třeba jej naplnit barvou BrushFillBack</summary>
		internal bool BackGroundRunSystem { get; set; }
		/// <summary>Rectangle představující pozadí, který se má vyplnit barvou BrushFillBack. Použije se, pokud není definován BackGroundPolygon, a pokud tento BackGroundRectangle není Empty. Jinak se použije this.DefaultDetailAreaBack</summary>
		internal Rectangle BackGroundRectangle { get; set; }
		/// <summary>Polygon představující linky okolo pozadí, kreslené barvou BackLinePenA. Typicky je null.</summary>
		internal Point[] BackGroundPolygonLineA { get; set; }
		/// <summary>Polygon představující linky okolo pozadí, kreslené barvou BackLinePenB. Typicky je null.</summary>
		internal Point[] BackGroundPolygonLineB { get; set; }
		/// <summary>Polygon představující pozadí, který se má vyplnit barvou BrushFillBack. Pokud není null, použije se prioritně. Obtáhne se barvou BackLinePen.</summary>
		internal Point[] BackGroundPolygon { get; set; }
		/// <summary>Štětec, který je definovaný pro plnění Background. Pokud je null, pak systém použije výchozí.</summary>
		internal Brush BackGroundBrush { get; set; }
		/// <summary>
		/// Barva štětce na pozadí, kterým se má vyplnit Background. 
		/// Použije se, pokud není definovaný štětec BackGroundBrush, a pokud tato barva není Empty (což je výchozí stav).
		/// Pokud nebude definovaný ani štětec BackGroundBrush, ani barva BackGroundColor, použije se pro vytvoření štětce systémová paleta.
		/// Systémovou paletou může být služba IGraphElementPalette, která pak bude generovat štětec ve své metodě GetBrush().
		/// Tento princip platí pro některé další položky.
		/// </summary>
		internal Color BackGroundColor { get; set; }
		/// <summary>Požadavek na Dispose nástroje BackGroundBrush po jeho použití (pokud prvek pochází z palety, nesmí se nastavit na true !)</summary>
		internal bool BackGroundBrushDispose { get; set; }

		/// <summary>Příznak, že painter definoval Rectangle BackGroundRectangle anebo polygon Point[] BackGroundPolygon, a je třeba jej orámovat perem BackLinePen</summary>
		internal bool BackLineRunSystem { get; set; }
		/// <summary>Pero, kterým se má orámovat Background. Pokud je null, pak systém použije výchozí.</summary>
		internal Pen BackLinePen { get; set; }
		/// <summary>Barva pera, kterým se má orámovat Background. Použije se, pokud není definované pero, a pokud tato barva není Empty (což je výchozí stav).</summary>
		internal Color BackLineColor { get; set; }
		/// <summary>Šířka pera, kterým se má orámovat Background. Použije se, pokud není definované pero, a pokud tato šířka je větší než 0 (což je výchozí stav).</summary>
		internal float BackLineWidth { get; set; }
		/// <summary>Požadavek na Dispose pera PenLineBack (protože bylo vytvořeno jako new jen pro tuto jednu operaci). Pokud je Pen přečten z palety, nesmí se nastavovat na true.</summary>
		internal bool BackLinePenDispose { get; set; }

		/// <summary>Pero, kterým se má orámovat BackGroundPolygonLineA. Pokud je null, pak systém použije výchozí.</summary>
		internal Pen BackLinePenA { get; set; }
		/// <summary>Barva pera, kterým se má orámovat BackGroundPolygonLineA. Použije se, pokud není definované pero, a pokud tato barva není Empty (což je výchozí stav).</summary>
		internal Color BackLineAColor { get; set; }
		/// <summary>Šířka pera, kterým se má orámovat BackGroundPolygonLineA. Použije se, pokud není definované pero, a pokud tato šířka je větší než 0 (což je výchozí stav).</summary>
		internal float BackLineAWidth { get; set; }
		/// <summary>Požadavek na Dispose pera PenLineBackA (protože bylo vytvořeno jako new jen pro tuto jednu operaci). Pokud je Pen přečten z palety, nesmí se nastavovat na true.</summary>
		internal bool BackLinePenADispose { get; set; }
		/// <summary>Pero, kterým se má orámovat BackGroundPolygonLineB. Pokud je null, pak systém použije výchozí.</summary>
		internal Pen BackLinePenB { get; set; }
		/// <summary>Barva pera, kterým se má orámovat BackGroundPolygonLineB. Použije se, pokud není definované pero, a pokud tato barva není Empty (což je výchozí stav).</summary>
		internal Color BackLineBColor { get; set; }
		/// <summary>Šířka pera, kterým se má orámovat BackGroundPolygonLineB. Použije se, pokud není definované pero, a pokud tato šířka je větší než 0 (což je výchozí stav).</summary>
		internal float BackLineBWidth { get; set; }
		/// <summary>Požadavek na Dispose pera PenLineBackB (protože bylo vytvořeno jako new jen pro tuto jednu operaci). Pokud je Pen přečten z palety, nesmí se nastavovat na true.</summary>
		internal bool BackLinePenBDispose { get; set; }

		/// <summary>Požadavek na spodní orámování = pod výplní a pod BackLine. Využívá Rectangle BackGroundRectangle anebo polygon Point[] BackGroundPolygon. Bude se kreslit POD všechny vrstvy.</summary>
		internal bool OuterLineRunSystem { get; set; }
		/// <summary>Pero, kterým se má orámovat Background. Pokud je null, pak systém použije výchozí.</summary>
		internal Pen OuterLinePen { get; set; }
		/// <summary>Barva pera, kterým se má orámovat Background. Použije se, pokud není definované pero, a pokud tato barva není Empty (což je výchozí stav).</summary>
		internal Color OuterLineColor { get; set; }
		/// <summary>Šířka pera, kterým se má orámovat Background. Typicky má být větší než BackLineWidth, aby bylo vidět.</summary>
		internal float OuterLineWidth { get; set; }
		/// <summary>Požadavek na Dispose pera OuterLinePen (protože bylo vytvořeno jako new jen pro tuto jednu operaci). Pokud je Pen přečten z palety, nesmí se nastavovat na true.</summary>
		internal bool OuterLinePenDispose { get; set; }

		/// <summary>Příznak, že painter definoval Rectangle BackGroundRectangle, a chce jej orámovat vlevo a vpravo perem PenLineBack</summary>
		internal bool BackSideRunSystem { get; set; }
		/// <summary>Minimální šířka elementu, pro kterou jsou vykreslovány boční linky.</summary>
		internal int BackSideMinElementWidth { get; set; }
		/// <summary>Šířka pera pro boční linky.</summary>
		internal Color BackSidePenColor { get; set; }
		/// <summary>Šířka pera pro boční linky.</summary>
		internal float BackSidePenWidth { get; set; }

		/// <summary>Příznak, že painter definoval Rectangle FillUtilR anebo polygon Point[] FillUtilP, a je třeba jej naplnit barvou BrushFillUtil</summary>
		internal bool UtilizationRunSystem { get; set; }
		/// <summary>Rectangle představující utilization, který se má vyplnit barvou BrushFillUtil</summary>
		internal Rectangle UtilizationRectangle { get; set; }
		/// <summary>Polygon představující utilization, který se má vyplnit barvou BrushFillUtil</summary>
		internal Point[] UtilizationPolygon { get; set; }
		/// <summary>Štětec, který je definovaný pro plnění Utilization. Pokud je null, pak systém použije výchozí.</summary>
		internal Brush UtilizationBrush { get; set; }
        /// <summary>Barva štětce, kterým se má vyplnit Utilization. POZOR: barva má reagovat na aktuální hodnotu využití kapacit args.DataElement.UtilizationRatio. Použije se, pokud není definovaný štětec, a pokud tato barva není Empty (což je výchozí stav).</summary>
		internal Color UtilizationColor { get; set; }
		/// <summary>Požadavek na Dispose prvku UtilizationBrush po jeho použití (pokud prvek pochází z palety, nesmí se nastavit na true !)</summary>
		internal bool UtilizationBrushDispose { get; set; }

		/// <summary>Příznak, že painter definoval sadu interních rectangle a barev pro vykreslení výplně</summary>
		internal bool InnerShapeRunSystem { get; set; }
		/// <summary>Souhrn inner tvarů</summary>
		internal List<InnerShapeCls> InnerShapeList
		{
			get
			{
				if (this._InnerShapeList == null)
				{
					this._InnerShapeList = new List<InnerShapeCls>();
					this.InnerShapeRunSystem = true;
				}
				return this._InnerShapeList;
			}
			set
			{
				this._InnerShapeList = value;
			}
		}
		private List<InnerShapeCls> _InnerShapeList;

		/// <summary>Příznak, že painter definoval polygon Point[] TopLinePolygon, a je třeba jej vykreslit perem TopLinePen nebo barvou TopLinePenColor</summary>
		internal bool TopLineRunSystem { get; set; }
		/// <summary>Suoupis bodů, které se mají vykreslit jako TopLine</summary>
		internal Point[] TopLinePolygon { get; set; }
		/// <summary>Pero, kterým se má orámovat Utilization. Pokud je null, pak systém použije výchozí.</summary>
		internal Pen TopLinePen { get; set; }
		/// <summary>Šířka pera pro horní linku.</summary>
		internal Color TopLinePenColor { get; set; }
		/// <summary>Šířka pera pro horní linku.</summary>
		internal float TopLinePenWidth { get; set; }
		/// <summary>Požadavek na Dispose prvku TopLinePen po jeho použití (pokud prvek pochází z palety, nesmí se nastavit na true !)</summary>
		internal bool TopLinePenDispose { get; set; }

		/// <summary>Příznak, že painter vyžaduje vykreslení Caption do elementu</summary>
		internal bool CaptionRunSystem { get; set; }
		/// <summary>Font pro kreslení popisku</summary>
		internal Font CaptionFont { get; set; }
		/// <summary>Explicitní text popisku</summary>
		internal string CaptionText { get; set; }
		/// <summary>Požadavek na Dispose nástroje CaptionFont po jeho použití (pokud prvek pochází z palety, nesmí se nastavit na true !)</summary>
		internal bool CaptionFontDispose { get; set; }
		/// <summary>Barva pro kreslení popisku</summary>
		internal Brush CaptionBrush { get; set; }
		/// <summary>Barva štětce, kterým se má psát text. Použije se, pokud není definovaný štětec, a pokud tato barva není Empty (což je výchozí stav).</summary>
		internal Color CaptionColor { get; set; }
		/// <summary>Požadavek na Dispose prvku CaptionBrush po jeho použití (pokud prvek pochází z palety, nesmí se nastavit na true !)</summary>
		internal bool CaptionBrushDispose { get; set; }
		/// <summary>Prostor pro kreslení Caption. Lze sem uložit this.DefaultCaptionArea, ale to zvládne defaultní painter taky.</summary>
		internal Rectangle CaptionArea { get; set; }

		/// <summary>Kreslit obrázek?</summary>
		internal bool ImageRunSystem { get; set; }
		/// <summary>Obrázek k vykreslení</summary>
		internal Image Image { get; set; }
		/// <summary>Prostor k vykreslení obrázku</summary>
		internal Rectangle ImageArea { get; set; }
		#endregion
		#region PROPERTY ROZŠÍŘENÉ
		/// <summary>
		/// Aktuální platná vizuální pozice položky grafu.
		/// Souřadnice jsou uvedeny v koordinátech Controlu, v němž je element vykreslen.
		/// Prostor je oříznutý do rozměrů aktuálního grafu (na rozdíl od ElementArea, který definuje pozici elementu v logickém prostoru grafu).
		/// Tento údaj se aktualizuje při každém vykreslení grafu.
		/// </summary>
        internal Rectangle VisualRectangle { get { return this.ChartElement.VisualRectangle; } set { this.ChartElement.VisualRectangle = value; } }
		/// <summary>
		/// Defaultní souřadnice pro VisualRectangle ( = Rectangle.Intersect(this.DetailArea, this.RowGraphArea) )
		/// </summary>
		internal Rectangle DefaultVisualRectangle { get { return Rectangle.Intersect(this.DetailArea, this.RowGraphArea); } }
		/// <summary>
		/// Implicitní prostor pro DetailAreaBack (pozadí) = prostor 
		/// ve fyzické souřadnici this.ElementArea(X,Y) + offset this.GraphElement.RectangleBack.Y (tzn. absolutní pozice prostoru grafu v řádku v controlu)
		/// ve velikosti this.GraphElement.RectangleBack (tzn. celá prostor elementu)
		/// </summary>
		internal Rectangle DefaultDetailAreaBack
		{
			get
			{
				Rectangle result = new Rectangle(
                    this.ElementArea.X, this.ElementArea.Y + this.ChartElement.RectangleBack.Y,
                    this.ChartElement.RectangleBack.Width, this.ChartElement.RectangleBack.Height);
				this.CheckRectangle(ref result);
				return result;
			}
		}
		/// <summary>
		/// Implicitní prostor pro DetailAreaElement (významová část grafu) = prostor 
		/// ve fyzické souřadnici this.ElementArea(X,Y) + offset this.GraphElement.ElementArea.Y (tzn. absolutní pozice prostoru grafu v řádku v controlu)
		/// ve velikosti this.GraphElement.ElementArea (tzn. vnitřní rozměr elementu)
		/// </summary>
		internal Rectangle DefaultDetailAreaElement
		{
			get
			{
				Rectangle result = new Rectangle(
                    this.ElementArea.X, this.ElementArea.Y + this.ChartElement.ElementArea.Y,
                    this.ElementArea.Width, this.ChartElement.ElementArea.Height);
				this.CheckRectangle(ref result);
				return result;
			}
		}
		/// <summary>
		/// Implicitní prostor pro Caption v elementu = prostor 
		/// ve v průsečíku (this.DetailArea, this.RowGraphArea), v případě potřeby zvětšený na výšku 14px
		/// </summary>
		internal Rectangle DefaultCaptionArea
		{
			get
			{
				Rectangle result = Rectangle.Intersect(this.DetailArea, this.RowGraphArea);
				result.Y += 1;
				if (result.Height < 14)
				{
					int vc = result.Y + result.Height / 2;
					result.Y = vc - 7;
					result.Height = 14;
				}
				this.CheckRectangle(ref result);
				return result;
			}
		}
		/// <summary>
		/// Zajistí, že daný rectangle bude fyzicky vykreslitelný (nebude příliš veliký z hlediska řádku).
		/// Pokud bude přesahovat doleva/doprava, pak maximálně o 100px.
		/// </summary>
		/// <param name="result"></param>
		internal void CheckRectangle(ref Rectangle result)
		{
			int x = result.X;
			int w = result.Width;
			int r = result.Right;
			bool change = false;

			int minX = this.RowGraphArea.X - 100;            // Souřadnice result jsou od té nuly, od které je i this.RowGraphArea.X
			int maxX = this.RowGraphArea.Right + 100;

			if (x < minX)
			{
				x = minX;
				w = r - x;
				change = true;
			}
			if (r > maxX)
			{
				r = maxX;
				w = r - x;
				change = true;
			}
			if (change)
			{
				result.X = x;
				result.Width = (w < 0 ? 0 : w);
			}
		}
		#endregion
		#region SUBCLASS InnerShapes : vnitřní obrazce s jednoduchou barvou
		/// <summary>
		/// Třída, která definuje vnitřní tvar uvnitř elementu.
		/// </summary>
		internal class InnerShapeCls
		{
			internal InnerShapeCls()
			{
				this.InnerRectangle = Rectangle.Empty;
				this.InnerBackColor = Color.Empty;
				this.InnerLineColor = Color.Empty;
			}
			internal InnerShapeCls(Rectangle innerRectangle, Color innerBackColor)
			{
				this.InnerRectangle = innerRectangle;
				this.InnerBackColor = innerBackColor;
				this.InnerLineColor = Color.Empty;
			}
			internal InnerShapeCls(Rectangle innerRectangle, Color innerBackColor, Color innerLineColor)
			{
				this.InnerRectangle = innerRectangle;
				this.InnerBackColor = innerBackColor;
				this.InnerLineColor = innerLineColor;
			}
			internal InnerShapeCls(Point[] innerPolygon, Color innerBackColor)
			{
				this.InnerRectangle = Rectangle.Empty;
				this.InnerPolygon = innerPolygon;
				this.InnerBackColor = innerBackColor;
				this.InnerLineColor = Color.Empty;
			}
			internal InnerShapeCls(Point[] innerPolygon, Color innerBackColor, Color innerLineColor)
			{
				this.InnerRectangle = Rectangle.Empty;
				this.InnerPolygon = innerPolygon;
				this.InnerBackColor = innerBackColor;
				this.InnerLineColor = innerLineColor;
			}
			/// <summary>Vnitřní prostor ve tvaru obdélníku - jeho tvar</summary>
			internal Rectangle InnerRectangle { get; set; }
			/// <summary>Vnitřní prostor ve tvaru polygonu - jeho tvar</summary>
			internal Point[] InnerPolygon { get; set; }
            /// <summary>Vnitřní prostor - jeho štětec pozadí, null = nebude použito</summary>
            internal Brush InnerBackBrush { get; set; }
            /// <summary>Vnitřní prostor - příznak, zda jeho štětec pozadí this.InnerBackBrush se má po použití disposnout (true = Dispose, false = nechat být)</summary>
            internal bool InnerBackBrushNeedDispose { get; set; }
            /// <summary>Vnitřní prostor - jeho barva pozadí, Empty = nebude vykresleno</summary>
			internal Color InnerBackColor { get; set; }
			/// <summary>Vnitřní prostor - jeho barva orámování, Empty = nebude vykresleno</summary>
			internal Color InnerLineColor { get; set; }
			/// <summary>Popisek vnitřního textu</summary>
			internal string InnerCaption { get; set; }
		}
		#endregion
        #region Obecná nastavení: stačí zavolat, a nastaví se defaultně celá sada prvků
        /// <summary>
        /// Nastav kreslení BackLine
        /// </summary>
        /// <param name="shrinkBgrInEditor">Pokud je element v editoru, má se zmenšovat jeho výška v BackGroundRectangle?  true = zmenšit / false = neměnit.</param>
        internal void BackLineSetSystem(bool shrinkBgrInEditor)
        {
            this.BackLineRunSystem = true;

            Rectangle back = this.BackGroundRectangle;
            int width = (!back.IsEmpty ? back.Width : 3);
            if (width >= 3)
            {   // Přiměřeně široké rámečky kresím běžně:

                if (this.ElementState == GraphElementState.Active || this.ElementState == GraphElementState.Selected)
                {
                    this.BackLineColor = Color.Yellow;
                    this.BackLineWidth = 1;
                }
                else if (this.ElementState == GraphElementState.InEditor)
                {   // Pokud je element v editoru (tzn. je propojen v síti vztahů), bude mít výraznější okraje (dvojité) a část svého vnitřku věnuje právě těmto okrajům:
                    if (shrinkBgrInEditor)
                    {
                        back.Y = back.Y + 1;
                        back.Height = back.Height - 2;
                        this.BackGroundRectangle = back;
                    }

                    this.BackLineColor = Color.Yellow;
                    this.BackLineWidth = 1;

                    this.OuterLineRunSystem = true;
                    this.OuterLineColor = Color.Magenta;
                    this.OuterLineWidth = 4;
                }
                else
                {
                    this.BackLineColor = Color.Black;
                    this.BackLineWidth = 1;
                }
            }
            else
            {   // Úzké rámečky kreslím tak, že background je plný, ale Line je jen nahoře a dole a kousek ze stran, ale uprostřed se čára nekreslí, prosvítá background:
                // Využívám ke kreslení property BackGroundPolygonLineA a BackGroundPolygonLineB:
                int x = back.X;
                int y = back.Y;
                int b = back.Bottom;
                int r = back.Right;
                int h = back.Height / 4;
                if (width >= 2)
                {   // 2 (a více?) pixely vedle sebe:
                    this.BackGroundPolygonLineA = new Point[]
                    {
                        new Point(x, y + h),
                        new Point(x, y),
                        new Point(r, y)
                    };
                    this.BackGroundPolygonLineB = new Point[]
                    {
                        new Point(x, b),
                        new Point(r, b),
                        new Point(r, b - h)
                    };
                }
                else
                {   // 1 pixel na výšku:
                    this.BackGroundPolygonLineA = new Point[]
                    {
                        new Point(x, y + h),
                        new Point(x, y)
                    };
                    this.BackGroundPolygonLineB = new Point[]
                    {
                        new Point(x, b),
                        new Point(x, b - h)
                    };
                }

                if (this.ElementState == GraphElementState.Active || this.ElementState == GraphElementState.Selected)
                    this.BackLineAColor = Color.Yellow;
                else if (this.ElementState == GraphElementState.InEditor)
                    this.BackLineAColor = Color.Magenta;
                else
                    this.BackLineAColor = Color.Black;

                this.BackLineAWidth = 1F;

                this.BackLineBColor = this.BackLineAColor;
                this.BackLineBWidth = this.BackLineAWidth;
            }

        }
        #endregion
    }
	#endregion
}
